package com.alibaba.citrus.cr.mn.order.center.facade.function.check;

import com.alibaba.citrus.cr.common.enums.ordercenter.*;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.common.util.DateUtils;
import com.alibaba.citrus.cr.mn.order.center.common.util.AssertUtils;
import com.alibaba.citrus.cr.mn.order.center.common.util.JsonUtils;
import com.alibaba.citrus.cr.mn.order.center.common.util.MoneyUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.BaseDataServiceAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.function.impl.ReturnOrderBizUpdateServiceImpl;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.epoch.app.mnordercenter.model.dto.DictionaryResponse;
import com.epoch.app.mnordercenter.orderbaserequest.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * @author liuyinhu
 * @ClassName ReturnOrderUpdateParamsBizCheck
 * @description:
 * @version: 1.0
 */
@Service
public class ReturnOrderUpdateParamsBizCheck extends AbstractOrderParamsCheckService<OrderBizUpdateRequest, OrderBizUpdateResponse> {

    private static final Log log = Log.getLogger(ReturnOrderUpdateParamsBizCheck.class);
    @Resource
    private BaseDataServiceAdapter baseDataServiceAdapter;

    @Override
    public void paramsNotBlankCheck(List<OrderBizUpdateRequest> requestList, List<OrderBizUpdateResponse> responseList) {
        requestList.forEach(request -> {
            AssertUtils.isTrue(StringUtils.isBlank(request.getFromSys()), "OC-01-001-01-15-001", "来源系统编码");
            AssertUtils.isTrue(StringUtils.isBlank(request.getBusinessType()), "OC-01-001-01-15-001", "业态编码");
            AssertUtils.isTrue(StringUtils.isBlank(request.getBusinessUnitCode()), "OC-01-001-01-15-001", "业务单元编码");
            AssertUtils.isTrue(StringUtils.isBlank(request.getSalesOrderNo()), "OC-01-001-01-15-001", "退货单单号");
            AssertUtils.isTrue(StringUtils.isBlank(request.getModifierCode()), "OC-01-001-01-15-001", "修改人工号");
            List<OrderLineAtomUpdateRequest> orderDetailsList = request.getOrderDetails();
            AssertUtils.isTrue(CollectionUtils.isEmpty(orderDetailsList), "OC-01-001-01-15-001", "单据明细列表");
            AssertUtils.isTrue(orderDetailsList.size() > 100, "OC-01-001-01-15-004", "单据明细列表", orderDetailsList.size(), "100");
            // 来源单号不能重复
            List<String> sameSourceLineNums = orderDetailsList.stream()
                    .map(OrderLineAtomUpdateRequest::getSourceLineNum)
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.toMap(p -> p, p -> 1, Integer::sum))
                    .entrySet().stream().filter(entry -> entry.getValue() > 1)
                    .map(Map.Entry::getKey).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(sameSourceLineNums)) {
                throw new FunctionException("OC-01-001-01-15-002", "来源单行号", StringUtils.join(sameSourceLineNums, ","));
            }
            // 明细行号不能重复
            List<String> sameSourceLines = orderDetailsList.stream()
                    .map(OrderLineAtomUpdateRequest::getLineNum)
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.toMap(p -> p, p -> 1, Integer::sum))
                    .entrySet().stream().filter(entry -> entry.getValue() > 1)
                    .map(Map.Entry::getKey).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(sameSourceLines)) {
                throw new FunctionException("OC-01-001-01-15-002", "行号", StringUtils.join(sameSourceLines, ","));
            }
            orderDetailsList.forEach(detail -> {
                AssertUtils.isTrue(StringUtils.isBlank(detail.getSourceLineNum()), "OC-01-001-01-15-001", "来源单行号");
                if (StringUtils.isBlank(detail.getLineNum())) {
                    // 新增明细校验
                    AssertUtils.isTrue(StringUtils.isBlank(detail.getProductQuantity()), "OC-01-001-01-15-001", "退货数量");
                    AssertUtils.isTrue(StringUtils.isBlank(detail.getProductCode()), "OC-01-001-01-15-001", "物料编码");
                    AssertUtils.isTrue(StringUtils.isBlank(detail.getSalesUnitCode()), "OC-01-001-01-15-001", "销售单位编码");
                    if (OrderCategoryEnum.GROUP.getCode().equals(request.getOrderCategoryCode())){
                        AssertUtils.isTrue(StringUtils.isBlank(detail.getInvoiceNo()), "OC-01-001-01-15-001", "发票号");
                        AssertUtils.isTrue(StringUtils.isBlank(detail.getInvoiceLineNo()), "OC-01-001-01-15-001", "发票行号");
                        AssertUtils.isTrue(StringUtils.isBlank(detail.getProductionDate()), "OC-01-001-01-15-001", "生产日期");
                    }
                    if (StringUtils.isBlank(detail.getShippingWarehouseCode())) {
                        if (StringUtils.isBlank(detail.getDeliveryFactoryCode()) && StringUtils.isBlank(detail.getStockCode())) {
                            throw new FunctionException("OC-01-001-01-15-010", "收货仓库编码、收货工厂编码、收货库存地点编码");
                        }
                        AssertUtils.isTrue(StringUtils.isBlank(detail.getDeliveryFactoryCode()), "OC-01-001-01-15-001", "收货工厂编码");
                        AssertUtils.isTrue(StringUtils.isBlank(detail.getStockCode()), "OC-01-001-01-15-001", "收货库存地点编码");
                    } else {
                        AssertUtils.isTrue(StringUtils.isBlank(detail.getShippingWarehouseCode()), "OC-01-001-01-15-001", "收货仓编码");
                    }
                }
            });
        });
    }

    @Override
    public void paramsLengthCheck(List<OrderBizUpdateRequest> requestList, List<OrderBizUpdateResponse> responseList) {
        requestList.forEach(t -> {
            AssertUtils.isNumber(t.getBusinessType(), true, "OC-01-001-01-15-006", "业态编码");
            AssertUtils.lengthCheck(t.getFromSys(), 50, true, "OC-01-001-01-15-004", "来源系统编码");
            AssertUtils.lengthCheck(t.getBusinessType(), 10, true, "OC-01-001-01-15-004", "业态编码");
            AssertUtils.lengthCheck(t.getBusinessUnitCode(), 50, true, "OC-01-001-01-15-004", "业务单元编码");
            AssertUtils.lengthCheck(t.getSalesOrderNo(), 50, true, "OC-01-001-01-15-004", "退货单单号");
            AssertUtils.lengthCheck(t.getShipToPartyCode(), 50, false, "OC-01-001-01-15-004", "客户送达方编码");
            AssertUtils.lengthCheck(t.getExpectedDeliveryDate(), 10, false, "OC-01-001-01-15-004", "期望交货日期");
            AssertUtils.lengthCheck(t.getDeliveryMethodCode(), 50, false, "OC-01-001-01-15-004", "配送方式编码");
            AssertUtils.lengthCheck(t.getNote(), 255, false, "OC-01-001-01-15-004", "备注");
            AssertUtils.lengthCheck(t.getBizFeatures(), 1024, false, "OC-01-001-01-15-004", "扩展字段(主单)");
            AssertUtils.lengthCheck(t.getModifierCode(), 50, true, "OC-01-001-01-15-004", "修改人工号");
            AssertUtils.lengthCheck(t.getOrderReasonCode(), 50, false, "OC-01-001-01-15-004", "订单原因编码");
            AssertUtils.lengthCheck(t.getCostCenterCode(), 50, false, "OC-01-001-01-15-004", "成本中心编码");
            t.getOrderDetails().forEach(detail -> {
                AssertUtils.lengthCheck(detail.getLineNum(), 10, false, "OC-01-001-01-15-004", "行号");
                AssertUtils.lengthCheck(detail.getSourceLineNum(), 10, true, "OC-01-001-01-15-004", "来源单行号");
                AssertUtils.lengthCheck(detail.getProductCode(), 50, false, "OC-01-001-01-15-004", "物料编码");
                AssertUtils.lengthCheck(detail.getSalesUnitCode(), 50, false, "OC-01-001-01-15-004", "销售单位编码");
                AssertUtils.lengthCheck(detail.getProductQuantity(), 10, false, "OC-01-001-01-15-004", "退货数量");
                AssertUtils.lengthCheck(detail.getNote(), 255, false, "OC-01-001-01-15-004", "订单行备注");
                AssertUtils.lengthCheck(detail.getBizFeatures(), 1024, false, "OC-01-001-01-15-004", "扩展字段(子单)");
                AssertUtils.lengthCheck(detail.getShippingWarehouseCode(), 50, false, "OC-01-001-01-15-004", "收货仓编码");
                AssertUtils.lengthCheck(detail.getDeliveryFactoryCode(), 50, false, "OC-01-001-01-15-004", "收货工厂编码");
                AssertUtils.lengthCheck(detail.getStockCode(), 50, false, "OC-01-001-01-15-004", "收货库存地点编码");
                AssertUtils.lengthCheck(detail.getProductionDate(), 10, false, "OC-01-001-01-15-004", "生产日期");
                AssertUtils.lengthCheck(detail.getInvoiceNo(), 50, false, "OC-01-001-01-15-004", "发票号");
                AssertUtils.lengthCheck(detail.getInvoiceLineNo(), 50, false, "OC-01-001-01-15-004", "发票行号");
                resetMoneyForNYC(detail);
            });
        });
    }

    @Override
    public void paramsEnumDictCheck(List<OrderBizUpdateRequest> requestList, List<OrderBizUpdateResponse> responseList) {
        // 系统来源
        List<DictionaryResponse> fromSysResponseList = baseDataServiceAdapter.queryDictionarys(DictionaryTypeEnum.FROM_SYS.getCode());
        Map<String, DictionaryResponse> fromSysMap = fromSysResponseList.stream().collect(Collectors.toMap(DictionaryResponse::getCode, Function.identity(), (k1, k2) -> k2));
        // 业态
        List<DictionaryResponse> businessTypeResponseList = baseDataServiceAdapter.queryDictionarys(DictionaryTypeEnum.BUSINESS_TYPE.getCode());
        Map<String, DictionaryResponse> businessTypeMap = businessTypeResponseList.stream().collect(Collectors.toMap(DictionaryResponse::getCode, Function.identity(), (k1, k2) -> k2));
        // 校验业务单元编码
        List<DictionaryResponse> businessUnitCodeList = baseDataServiceAdapter.queryDictionarys(DictionaryTypeEnum.BUSINESS_UNIT_CODE.getCode());
        Map<String, DictionaryResponse> businessUnitCodeMap = businessUnitCodeList.stream().collect(Collectors.toMap(DictionaryResponse::getCode, Function.identity(), (k1, k2) -> k2));

        requestList.forEach(t -> {
            if (fromSysMap.get(t.getFromSys()) == null) {
                throw new FunctionException("OC-01-001-01-15-006", "来源系统编码");
            }
            if (businessTypeMap.get(t.getBusinessType()) == null) {
                throw new FunctionException("OC-01-001-01-15-006", "业态编码");
            }
            if (businessUnitCodeMap.get(t.getBusinessUnitCode()) == null) {
                throw new FunctionException("OC-01-001-01-15-006", "业务单元编码");
            }
            if (StringUtils.isNotBlank(t.getDeliveryMethodCode())) {
                SalesOrderDeliveryMethodEnum salesOrderDeliveryMethodEnum = SalesOrderDeliveryMethodEnum.of(t.getDeliveryMethodCode());
                Optional.ofNullable(salesOrderDeliveryMethodEnum).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "配送方式编码"));
                t.setDeliveryMethodName(salesOrderDeliveryMethodEnum.getDesc());
            }
            if (StringUtils.isNotBlank(t.getOrderReasonCode())) {
                SalesOrderReasonEnum salesOrderReasonEnum = SalesOrderReasonEnum.of(t.getOrderReasonCode());
                Optional.ofNullable(salesOrderReasonEnum).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "订单原因编码"));
                t.setOrderReasonName(salesOrderReasonEnum.getDesc());
            }
            if (StringUtils.isNotBlank(t.getExpectedDeliveryDate())) {
                AssertUtils.isTrue(!DateUtils.isDateFormat(t.getExpectedDeliveryDate()), "OC-00-001-01-15-001", "期望交货日期");
            }
            if (StringUtils.isNotBlank(t.getBizFeatures())) {
                AssertUtils.isTrue(!JsonUtils.isValidJson(t.getBizFeatures()), "OC-00-001-01-15-001", "扩展字段(主单)");
            }
            t.getOrderDetails().forEach(p -> {
                if (StringUtils.isBlank(p.getLineNum())) {
                    StockUnitEnum salesUnit = StockUnitEnum.of(p.getSalesUnitCode());
                    Optional.ofNullable(salesUnit).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "销售单位编码"));
                    AssertUtils.isWholeNumber(p.getProductQuantity(), true, "OC-00-001-01-15-001", "退货数量");
                    AssertUtils.isTrue(new BigDecimal("2147483647").compareTo(new BigDecimal(p.getProductQuantity())) < 0, "OC-01-001-01-15-009", "退货数量", "最大2147483647");
                    AssertUtils.isTrue(BigDecimal.ZERO.compareTo(new BigDecimal(p.getProductQuantity())) >= 0, "OC-01-001-01-15-009", "退货数量", "不允许为零或负数");
                } else {
                    if (StringUtils.isNotBlank(p.getSalesUnitCode())) {
                        StockUnitEnum salesUnit = StockUnitEnum.of(p.getSalesUnitCode());
                        Optional.ofNullable(salesUnit).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "销售单位编码"));
                    }
                    if (StringUtils.isNotBlank(p.getProductQuantity())) {
                        AssertUtils.isWholeNumber(p.getProductQuantity(), true, "OC-00-001-01-15-001", "退货数量");
                        AssertUtils.isTrue(new BigDecimal("2147483647").compareTo(new BigDecimal(p.getProductQuantity())) < 0, "OC-01-001-01-15-009", "退货数量", "最大2147483647");
                        AssertUtils.isTrue(BigDecimal.ZERO.compareTo(new BigDecimal(p.getProductQuantity())) >= 0, "OC-01-001-01-15-009", "退货数量", "不允许为零或负数");
                    }
                }
                if (StringUtils.isNotBlank(p.getProductionDate())) {
                    AssertUtils.isTrue(!DateUtils.isDateFormat(p.getProductionDate()), "OC-00-001-01-15-001", "生产日期");
                }
                if (StringUtils.isNotBlank(p.getBizFeatures())) {
                    AssertUtils.isTrue(!JsonUtils.isValidJson(p.getBizFeatures()), "OC-00-001-01-15-001", "扩展字段(子单)");
                }

            });
        });

    }

    /**
     * 金额转换 元转分
     */
    static void resetMoneyForNYC(OrderLineAtomUpdateRequest request) {
        request.setUnitPrice(MoneyUtils.moneyStrYuan2Fen(request.getUnitPrice()));
        request.setTotalAmount(MoneyUtils.moneyStrYuan2Fen(request.getTotalAmount()));
        request.setManualPrice(MoneyUtils.moneyStrYuan2Fen(request.getManualPrice()));
        request.setManualTotalAmount(MoneyUtils.moneyStrYuan2Fen(request.getManualTotalAmount()));
        request.setActivityPrice(MoneyUtils.moneyStrYuan2Fen(request.getActivityPrice()));
        request.setActivityTotalAmount(MoneyUtils.moneyStrYuan2Fen(request.getActivityTotalAmount()));
    }
}
